<pre class='metadata'>
Title: CSS Shadow Parts Module Level 1
Shortname: css-shadow-parts
Level: 1
Group: CSSWG
Status: ED
Work Status: exploring
URL: http://drafts.csswg.org/css-shadow-parts/
TR: https://www.w3.org/TR/css-shadow-parts-1/
Editor: Tab Atkins-Bittner, Google, http://xanthir.com/contact/, w3cid 42199
Editor: Fergal Daly, Google, fergal@chromium.org
Abstract: This specification defines the ''::part()'' pseudo-element on <a>shadow hosts</a>, allowing <a>shadow hosts</a> to selectively expose chosen elements from their <a>shadow tree</a> to the outside page for styling purposes.
WPT Path Prefix: css/css-shadow-parts/
WPT Display: open
</pre>

<pre class=link-defaults>
spec:selectors-4;
	type:selector; text::hover
	type:dfn; text:live profile
	type:dfn; text:structural pseudo-class
spec:dom; type:dfn; for:/; text:shadow root
spec:infra;
	type:dfn;
		text:string
		text:list
</pre>

Introduction {#intro}
=====================

Shadow DOM allows authors to separate their page into "components",
subtrees of markup whose details are only relevant to the component itself,
not the outside page.
This reduces the chance of a style meant for one part of the page
accidentally over-applying and making a different part of the page look wrong.
However, this styling barrier also makes it harder for a page to interact with its components
when it actually <em>wants</em> to do so.

This specification defines the ''::part()'' pseudo-element,
which allows an author to style specific, purposely exposed elements in a <a>shadow tree</a>
from the outside page's context.
In combination with <a>custom properties</a>,
which let the outside page pass particular values
(such as theme colors)
into the component for it to do with as it will,
these pseudo-elements allow components and the outside page
to interact in safe, powerful ways,
maintaining encapsulation
without surrendering all control.

<wpt title="General tests for shadow parts">
	all-hosts.html
	animation-part.html
	chaining-invalid-selector.html
	complex-matching.html
	complex-non-matching.html
	different-host.html
	double-forward.html
	grouping-with-checked.html
	grouping-with-disabled.html
	host-stylesheet.html
	inner-host.html
	interaction-with-nested-pseudo-class.html
	interaction-with-placeholder.html
	interaction-with-pseudo-elements.html
	invalidation-complex-selector-forward.html
	invalidation-complex-selector.html
	invalidation-part-pseudo.html
	multiple-parts.html
	part-after-combinator-invalidation.html
	part-mutation-pseudo.html
	part-nested-pseudo.html
	precedence-part-vs-part.html
	pseudo-classes-after-part.html
	pseudo-elements-after-part.html
	serialization.html
	simple-forward-shorthand.html
	simple-forward.html
	simple-important.html
	simple-important-important.html
	simple-important-inline.html
	simple.html
	simple-important.html
	simple-inline.html
	style-sharing.html
</wpt>

Motivation {#motivation}
------------------------

For custom elements to be fully useful and as capable as built-in elements
it should be possible for parts of them to be styled from outside.
Exactly what can be styled from outside should be controlled by the element author.
Also, it should be possible for a custom element to present a stable "API" for styling.
That is, the selector used to style a part of a custom element
should not expose or require knowledge of the internal details of the element.
The custom element author should be able to change the internal details of the element
while leaving the selectors untouched.

The previous proposed method for styling inside the shadow tree,
the >>> combinator,
turned out to be <em>too powerful</em> for its own good;
it exposed too much of a component's internal structure to scrutiny,
defeating some of the encapsulation benefits that using Shadow DOM brings.
For this,
and other performance-related reasons,
the >>> combinator was eventually dropped.

This left us with using <a>custom properties</a> as the only way to style into a shadow tree:
the component would advertise that it uses certain <a>custom properties</a> to style its internals,
and the outer page could then set those properties as it wished on the <a>shadow host</a>,
letting inheritance push the values down to where they were needed.
This works very well for many simple theming use-cases.

However, there are some cases where this falls down.
If a component wishes to allow arbitrary styling of something in its shadow tree,
the only way to do so is to define hundreds of <a>custom properties</a>
(one per CSS property they wish to allow control of),
which is obviously ridiculous
for both usability and performance reasons.
The situation is compounded if authors wish to style the component differently
based on pseudo-classes like '':hover'';
the component needs to duplicate the <a>custom properties</a> used
for each pseudo-class
(and each combination,
like '':hover:focus'',
resulting in a combinatorial explosion).
This makes the usability and performance problems even worse.

We introduce ''::part()'' to handle this case much more elegantly and performantly.
Rather than bundling everything into <a>custom property</a> names,
the functionality lives in selectors and style rule syntax,
like it's meant to.
This is far more usable for both component authors
and component users,
should have much better performance,
and allows for better encapsulation/API surface.

It's important to note that ''::part()''
offers <em>absolutely zero new theoretical power</em>.
It is not a rehash of the <css>>>></css> combinator,
it is simply a more convenient and consistent syntax
for something authors can already do with <a>custom properties</a>.
By separating out the explicitly "published" parts of an element
(the <a>part element map</a>)
from the sub-parts that it merely happens to contain,
it also helps with encapsulation,
as authors can use ''::part()'' without fear of accidental over-styling.

<!-- Big Text: parts

████▌   ███▌  ████▌  █████▌  ███▌
█▌  █▌ ▐█ ▐█  █▌  █▌   █▌   █▌  █▌
█▌  █▌ █▌  █▌ █▌  █▌   █▌   █▌
████▌  █▌  █▌ ████▌    █▌    ███▌
█▌     █████▌ █▌▐█     █▌       █▌
█▌     █▌  █▌ █▌ ▐█    █▌   █▌  █▌
█▌     █▌  █▌ █▌  █▌   █▌    ███▌
-->
Exposing a Shadow Element: {#exposing}
=============================================================
Elements in a <a>shadow tree</a> may be exported for styling by stylesheets outside the tree
using the part and exportparts attributes.

Each element has a <dfn export for="element">part name list</dfn>
which is an [=ordered set=] of tokens.

Each element has a <dfn export for="element">forwarded part name list</dfn>
which is a [=list=] of [=tuples=]
containing a [=string=] for the inner part being forwarded
and a [=string=] giving the name it will be exposed as.

Each <a>shadow root</a> can be thought of as having a <dfn export for="shadow root">part element map</dfn>
with keys that are [=strings=]
and values that are [=ordered sets=] of elements.

The [=part element map=] is described
only as part of the algorithm for calculating style in this spec.
It is not exposed via the DOM,
as calculating it may be expensive
and exposing it could allow access to elements inside closed shadow roots.

[=Part element maps=] are affected by the addition and removal of elements
and changes to the [=part name lists=] and [=forwarded part name lists=] of elements in the DOM.

<div algorithm>
	To <dfn>calculate the [=part element map=]</dfn> of a shadow root, |outerRoot|:

	1. For each [=descendant=] |el| within |outerRoot|:
		1. For each |name| in |el|'s [=part name list=],
			[=list/append=] |el| to |outerRoot|'s [=part element map=][|name|].
		2. If |el| is a [=shadow host=] itself
			then let |innerRoot| be its shadow root.
		3. [=calculate the part element map|Calculate=] |innerRoot|'s [=part element map=].
		4. For each |innerName|/|outerName| in |el|'s [=forwarded part name list=]:
			1. If |innerName| is an ident:
				1. Let |innerParts| be |innerRoot|'s [=part element map=][|innerName|]
				2. [=list/Append=] the elements in |innerParts|
					to |outerRoot|'s [=part element map=][|outerName|]
			2. If |innerName| is a pseudo-element name:
				1. [=list/Append=] |innerRoot|'s pseudo-element(s) with that name
					to |outerRoot|'s [=part element map=][|outerName|].
</div>

<!-- Big Text: part=""

████▌   ███▌  ████▌  █████▌      ▐█▌ ▐█▌ ▐█▌ ▐█▌
█▌  █▌ ▐█ ▐█  █▌  █▌   █▌        ▐█▌ ▐█▌ ▐█▌ ▐█▌
█▌  █▌ █▌  █▌ █▌  █▌   █▌   ████  █   █   █   █
████▌  █▌  █▌ ████▌    █▌
█▌     █████▌ █▌▐█     █▌   ████
█▌     █▌  █▌ █▌ ▐█    █▌
█▌     █▌  █▌ █▌  █▌   █▌
-->
Naming a Shadow Element: the <{html-global/part}> attribute {#part-attr}
------------------------------------------------------------------------

Any element in a shadow tree can have a <dfn element-attr for=html-global>part</dfn> attribute.
This is used to expose the element outside of the <a>shadow tree</a>.

<wpt>
	invalidation-change-part-name-forward.html
	invalidation-change-part-name.html
</wpt>

The part attribute is parsed as a space-separated list of tokens representing the part names of this element.

Note: It's okay to give a part multiple names.
The "part name" should be considered similar to a class,
not an id or tagname.

<pre class="example">
&lt;style>
	c-e<b>::part(textspan)</b> { color: red; }
&lt;/style>

&lt;template id="c-e-template">
	&lt;span <b>part="textspan"</b>>This text will be red&lt;/span>
&lt;/template>
&lt;c-e>&lt;/c-e>
&lt;script>
	// Add template as custom element c-e
	...
&lt;/script>
</pre>

<!-- Big Text: exportparts

█████▌ █     █ ████▌   ███▌  ████▌  █████▌ ████▌   ███▌  ████▌  █████▌  ███▌
█▌      █   █  █▌  █▌ █▌  █▌ █▌  █▌   █▌   █▌  █▌ ▐█ ▐█  █▌  █▌   █▌   █▌  █▌
█▌       █ █   █▌  █▌ █▌  █▌ █▌  █▌   █▌   █▌  █▌ █▌  █▌ █▌  █▌   █▌   █▌
████      █    ████▌  █▌  █▌ ████▌    █▌   ████▌  █▌  █▌ ████▌    █▌    ███▌
█▌       █ █   █▌     █▌  █▌ █▌▐█     █▌   █▌     █████▌ █▌▐█     █▌       █▌
█▌      █   █  █▌     █▌  █▌ █▌ ▐█    █▌   █▌     █▌  █▌ █▌ ▐█    █▌   █▌  █▌
█████▌ █     █ █▌      ███▌  █▌  █▌   █▌   █▌     █▌  █▌ █▌  █▌   █▌    ███▌
-->
Forwarding a Shadow Element: the <{html-global/exportparts}> attribute {#exportparts-attr}
----------------------------------------------------------------------------------
Any element in a shadow tree can have a <dfn element-attr for=html-global>exportparts</dfn> attribute.
If the element is a shadow host,
this is used to allow styling of parts from hosts inside the <a>shadow tree</a>
by rules outside this the <a>shadow tree</a>
(as if they were elements in the same tree as the host,
named by a part attribute).

<wpt>
	both-part-and-exportparts.html
	exportparts-different-scope.html
	exportparts-layered.html
	exportparts-multiple.html
	invalidation-change-exportparts-forward.html
</wpt>

The exportparts attribute is parsed as a comma-separated list of part mappings.
Each part mapping is one of:

<dl class=switch>
	: <code>innerIdent : outerIdent</code>
	:: Adds <code>innerIdent</code>/<code>outerIdent</code> to el's <a>forwarded part name list</a>.

	: <code>ident</code>
	:: Adds <code>ident</code>/<code>ident</code> to el's <a>forwarded part name list</a>.

		Note: This is shorthand for <code>ident : ident</code>.

	: <code>::ident : outerIdent</code>
	:: If <code>::ident</code> is the name of a [=fully styleable pseudo-element=],
		adds <code>::ident</code>/<code>outerIdent</code>
		to el's [=forward part name list=].
		Otherwise, does nothing.

	: anything else
	:: Ignored for error-recovery / future compatibility.
</dl>

Note: It's okay to map a sub-part to several names.

<pre class="example">
&lt;style>
	c-e<b>::part(textspan)</b> { color: red; }
&lt;/style>

&lt;template id="c-e-outer-template">
	&lt;c-e-inner <b>exportparts="innerspan: textspan"</b>>&lt;/c-e-inner>
&lt;/template>

&lt;template id="c-e-inner-template">
	&lt;span <b>part="innerspan"</b>>
		This text will be red because the containing shadow
		host forwards <b>innerspan</b> to the document as "textspan"
		and the document style matches it.
	&lt;/span>
	&lt;span <b>part="textspan"</b>>
		This text will not be red because <b>textspan</b> in the document style
		cannot match against the part inside the inner custom element
		if it is not forwarded.
	&lt;/span>
&lt;/template>

&lt;c-e>&lt;/c-e>
&lt;script>
	// Add template as custom elements c-e-inner, c-e-outer
	...
&lt;/script>
</pre>

<div class=example>
	For example, a [=fully styleable pseudo-element=]
	can be used in the <{html-global/exportparts}> attribute,
	to masquerade as a ''::part()''
	for the component it's in:

	<xmp class=html>
		<template id=custom-element-template>
			<p exportparts="::before : preceding-text, ::after : following-text">
				Main text.
		</template>
	</xmp>

	An element using that template
	can use a selector like ''x-component::part(preceding-text)''
	to target the ''p::before'' pseudo-element in its shadow,
	so users of the component don't need to know
	that the preceding text is implemented as a pseudo-element.
</div>


<!-- Big Text: ::part()

 █▌   █▌  ████▌   ███▌  ████▌  █████▌   ██ ██
███▌ ███▌ █▌  █▌ ▐█ ▐█  █▌  █▌   █▌    █▌   ▐█
 █▌   █▌  █▌  █▌ █▌  █▌ █▌  █▌   █▌   █▌     ▐█
		  ████▌  █▌  █▌ ████▌    █▌   █▌     ▐█
 █▌   █▌  █▌     █████▌ █▌▐█     █▌   █▌     ▐█
███▌ ███▌ █▌     █▌  █▌ █▌ ▐█    █▌    █▌   ▐█
 █▌   █▌  █▌     █▌  █▌ █▌  █▌   █▌     ██ ██
-->

Selecting a Shadow Element: the ''::part()'' pseudo-element {#part}
===================================================================

The <dfn selector>::part()</dfn> pseudo-element
allows you to select elements that have been exposed via a <{html-global/part}> attribute.
The syntax is:

<pre class=prod>
	::part() = ::part( <<ident>>+ )
</pre>

<wpt>
	host-part-001.html
	host-part-002.html
	host-part-003.html
	host-part-nesting.html
	multiple-scopes.html
</wpt>

The ''::part()'' pseudo-element only matches anything
when the <a>originating element</a> is a <a>shadow host</a>.

<div class="example">
	For example,
	if you have a custom button
	that contains a "label" element that is exposed for styling
	(via <code>part="label"</code>),
	you can select it with
	''x-button::part(label)''.
</div>

<div class="example">
	Part names act similarly to classes:
	multiple elements can have the same part name,
	and a single element can have multiple part names.

	A tabstrip control might have multiple elements
	with <code>part="tab"</code>,
	all of which are selected by ''::part(tab)''.

	If a single tab is active at a time,
	it can be specially indicated with <code>part="tab active"</code>
	and then selected by ''::part(tab active)''
	(or ''::part(active tab)'', as order doesn't matter).
</div>

The ''::part()'' pseudo-element is a [=fully styleable pseudo-element=].
If the <a>originating element's</a> <a>shadow root's</a> <a>part element map</a>
[=map/contains=] the specified <<ident>>,
''::part()'' represents the elements keyed to that ident;
if multiple idents are provided and the [=part element map=] contains them all,
it represents the intersection of the elements keyed to each ident.
Otherwise, it matches nothing.

''::part()'' pseudo-elements inherit according to their position
in the [=originating element's=] shadow tree.

<div class=example>
	For example,
	''x-panel::part(confirm-button)::part(label)''
	never matches anything.
	This is because doing so would expose more structural information
	than is intended.

	If the <code>&lt;x-panel></code>'s internal confirm button had used something like
	<code>part="label => confirm-label"</code>
	to forward the button's internal parts up into the panel's own <a>part element map</a>,
	then a selector like
	''x-panel::part(confirm-label)''
	would select just the one button's label,
	ignoring any other labels.
</div>


<!-- Big Text: CSSOM

 ███▌   ███▌   ███▌   ███▌  █     █
█▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌ ██   ██
█▌     █▌     █▌     █▌  █▌ █▌█ █▐█
█▌      ███▌   ███▌  █▌  █▌ █▌ █ ▐█
█▌         █▌     █▌ █▌  █▌ █▌   ▐█
█▌  █▌ █▌  █▌ █▌  █▌ █▌  █▌ █▌   ▐█
 ███▌   ███▌   ███▌   ███▌  █▌   ▐█
-->

Extensions to the {{Element}} Interface {#idl}
==============================================

<pre class=idl>
partial interface Element {
	[SameObject, PutForwards=value] readonly attribute DOMTokenList part;
};
</pre>

<wpt>
	idlharness.html
	invalidation-change-part-name-idl-domtokenlist.html
	invalidation-change-part-name-idl-setter.html
	part-name-idl.html
</wpt>

The part attribute’s getter must return a DOMTokenList object
whose associated element is the context object
and whose associated attribute’s local name is part.
The token set of this particular DOMTokenList object are also known as the element’s parts.

Issue(w3c/csswg-drafts#3424): Define this as a superglobal in the DOM spec.

Microsyntaxes for parsing {#parsing}
==============================================

Rules for parsing part mappings {#parsing-mapping}
----------------------------------------------

A <dfn export>valid part mapping</dfn> is a [=tuple=] of tokens
separated by a U+003A COLON character
and any number of space characters before or after the U+003A COLON
The tokens must not contain U+003A COLON or U+002C COMMA characters.

The rules for parsing a part mapping are as follows:

1. Let <var>input</var> be the string being parsed.

1. Let <var>position</var> be a pointer into <var>input</var>, initially pointing at the start of the string.

1. [=Collect a sequence of code points=] that are space characters
1. [=Collect a sequence of code points=] that are not space characters or U+003A COLON characters,
	and let <var>first token</var> be the result.
1. If <var>first token</var> is empty then return error.
1. [=Collect a sequence of code points=] that are space characters.
1. If the end of the <var>input</var> has been reached, return the [=tuple=] (<var>first token</var>, <var>first token</var>)
1. If character at <var>position</var> is not a U+003A COLON character, return error.
1. Consume the U+003A COLON character.
1. [=Collect a sequence of code points=] that are space characters.
1. [=Collect a sequence of code points=] that are not space characters or U+003A COLON characters.
	and let <var>second token</var> be the result.
1. If <var>second token</var> is empty then return error.
1. [=Collect a sequence of code points=] that are space characters.
1. If <var>position</var> is not past the end of <var>input</var> then return error.
1. Return the [=tuple=] (<var>first token</var>, <var>second token</var>).

Rules for parsing a list of part mappings {#parsing-mapping-list}
----------------------------------------------

A <dfn export>valid list of part mappings</dfn> is a number of valid part mappings
separated by a U+002C COMMA character
and any number of space characters before or after the U+002C COMMA

The rules for parsing a list of part mappings are as follow:

1. Let <var>input</var> be the string being parsed.

1. [=split a string on commas|Split the string <var>input</var> on commas=].
	Let <var>unparsed mappings</var> be the resulting list of strings.

1. Let <var>mappings</var> be an initially empty [=list=] of [=tuples=] of tokens.
	This [=list=] will be the result of this algorithm.

1. For each string <var>unparsed mapping</var> in <var>unparsed mappings</var>,
	run the following substeps:

	1. If <var>unparsed mapping</var> is empty or contains only space characters,
		continue to the next iteration of the loop.
	1. Let <var>mapping</var> be the result of parsing <var>unparsed mapping</var>
		using the <span>rules for parsing part mappings</span>.
	1. If <var>mapping</var> is an error then continue to the next iteration of the loop.
		This allows clients to skip over new syntax that is not understood.
	1. Append <var>mapping</var> to <var>mappings</var>.

<h2 id=priv>
Privacy Considerations</h2>

This specification defines new ways to target styling of elements on the page,
which are already fully styleable in other ways.
As such, it introduces no new privacy considerations.

<h2 id=sec>
Security Considerations</h2>

As [=shadow trees=] are intentionally not a security boundary,
merely a convenience for page authors,
exposing them to selectors in this way introduces no new security considerations.

<h2 id=changes>
Changes</h2>

Changes since the <a href="https://www.w3.org/TR/2018/WD-css-shadow-parts-1-20181115/">
First Public Working Draft</a> of 15 November 2018

* Add support for multiple names in ''::part()''
* Renamed 'part name map' to [=forwarded part name list=]
* Restructured 'part element list' algorithm
* Moved various ''::part()'' details to [=fully styleable pseudo-element=]
* Added Web Platform Tests coverage
* Minor editorial improvements